package com.atguigu.gmall.order.receiver;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.client.PaymentFeignClient;
import com.atguigu.gmall.constant.MqConst;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.payment.PaymentInfo;
import com.atguigu.gmall.order.service.OrderService;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author mgx
 * @create 2024-09-04 11:14
 * @Description 订单监听器
 */
@Component
@SuppressWarnings("all")
public class OrderReceiver {

    @Autowired
    private OrderService orderService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PaymentFeignClient paymentFeignClient;

    /**
     * 仓储服务回调-扣减库存-更新订单状态
     * @param strJson
     * @param message
     * @param channel
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_WARE_ORDER, durable = "true"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_WARE_ORDER),
                    key = MqConst.ROUTING_WARE_ORDER
            )
    })
    @SneakyThrows
    public void stockOrderStatus(String strJson, Message message, Channel channel) {
        try {
            if(!StringUtils.isEmpty(strJson)){
                // 数据转化
                Map<String, String> map = JSON.parseObject(strJson, Map.class);
                String orderId = map.get("orderId");
                String status = map.get("status");
                if("DEDUCTED".equals(status)) {
                    // 扣减库存成功，更新订单状态为待发货
                    orderService.updateOrderStatus(Long.parseLong(orderId), ProcessStatus.WAITING_DELEVER);
                }else {
                    // 扣减库存异常，更新订单状态为库存异常
                    orderService.updateOrderStatus(Long.parseLong(orderId), ProcessStatus.STOCK_EXCEPTION);
                }
            }
        } catch (NumberFormatException e) {
            //出现异常，邮件短信等通知
            throw new RuntimeException(e);
        }
        // 手动确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /**
     * 订单支付成功-更新订单状态
     * @param orderId
     * @param message
     * @param channel
     */
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_PAYMENT_PAY, durable = "true"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_PAYMENT_PAY),
                    key = MqConst.ROUTING_PAYMENT_PAY
            )
    })
    @SneakyThrows
    public void paySuccess(Long orderId, Message message, Channel channel) {
        try {
            if(orderId != null) {
                // 查询订单信息
                OrderInfo orderInfo = orderService.getById(orderId);
                if(orderInfo != null && orderInfo.getOrderStatus().equals(ProcessStatus.UNPAID.getOrderStatus().name())) {
                    // 修改订单状态
                    orderService.updateOrderStatus(orderId, ProcessStatus.PAID);
                    // 通知仓储扣减库存
                    orderService.sendOrderStatus(orderId);
                }
            }
        } catch (Exception e) {
            //日志，短信通知
            throw new RuntimeException(e);
        }
        // 手动确认消息
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    @SneakyThrows
    @RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
    public void cancelOrder(Long orderId, Message message, Channel channel) {
        try {
            if (orderId != null) {
                // 查询订单
                OrderInfo orderInfo = orderService.getById(orderId);
                if (orderInfo != null) {
                    // 判断订单状态和进度状态
                    if ("UNPAID".equals(orderInfo.getOrderStatus()) && "UNPAID".equals(orderInfo.getProcessStatus())) {

                        // TODO 远程查询订单支付记录paymentInfo - PaymentFeignClient
                        PaymentInfo paymentInfo = paymentFeignClient.getPaymentInfo(orderInfo.getOutTradeNo());
                        if(paymentInfo != null) {
                            // 判断 -- 有
                            // 查询支付宝交易记录 -- PaymentFeignClient
                            Boolean isExist = paymentFeignClient.checkPayment(orderId);
                            if(isExist) {
                                // 判断 -- 有
                                // 关闭 -- 支付宝交易记录、支付记录、订单记录
                                Boolean aliClose = paymentFeignClient.closePay(orderId);
                                if(aliClose) {
                                    // 关闭支付宝交易记录成功后，关闭订单和本地支付记录
                                    orderService.execExpiredOrder(orderId, "2");
                                }else {
                                    // 关闭支付宝失败，有可能是因为已经支付了
                                    // TODO 考虑做后续处理
                                }
                            }else {
                                // 没有的话 -- 关闭订单和支付记录
                                orderService.execExpiredOrder(orderId, "2");
                            }

                        }else {
                            // 没有支付记录 -- 只关闭订单
                            orderService.execExpiredOrder(orderId, "1");
                        }
                    }
                }
            }
        } catch (Exception e) {
            //  消息没有正常被消费者处理： 记录日志后续跟踪处理!
            e.printStackTrace();
        }

        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    // 做幂等性的方法
   /* @SneakyThrows
    @RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
    public void cancelOrderAdvanced(Long orderId, Message message, Channel channel) {
        try {
            if (orderId != null) {
                String msgKey = "delay:" + orderId;
                // 查询订单
                OrderInfo orderInfo = orderService.getById(orderId);
                if (orderInfo != null) {
                    Boolean result = redisTemplate.opsForValue().setIfAbsent(msgKey, "0", 10, TimeUnit.MINUTES);
                    if (!result) {
                        // 已经有已知的消息
                        String isConsume = (String) redisTemplate.opsForValue().get(msgKey);
                        if ("1".equals(isConsume)) {
                            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                        } else {
                            // 判断订单状态和进度状态
                            if ("UNPAID".equals(orderInfo.getOrderStatus()) && "UNPAID".equals(orderInfo.getProcessStatus())) {
                                // 关闭订单, 更新订单状态
                                orderService.execExpiredOrder(orderId);
                                redisTemplate.opsForValue().set(msgKey, "1");
                                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                            }
                        }
                    } else {
                        // 第一次消费
                        // 判断订单状态和进度状态
                        if ("UNPAID".equals(orderInfo.getOrderStatus()) && "UNPAID".equals(orderInfo.getProcessStatus())) {
                            // 关闭订单, 更新订单状态
                            orderService.execExpiredOrder(orderId);
                            redisTemplate.opsForValue().set(msgKey, "1");
                            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                        }
                    }
                }
            }
        } catch (Exception e) {
            //  消息没有正常被消费者处理： 记录日志后续跟踪处理!
            e.printStackTrace();
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }*/
}
